తెలుగు

టైప్‌స్క్రిప్ట్ జెనెరిక్స్ పై ఒక సమగ్ర మార్గదర్శిని. గ్లోబల్ సాఫ్ట్‌వేర్ అభివృద్ధిలో సంక్లిష్ట డేటా రకాలను నిర్వహించడానికి దీని సింటాక్స్, ప్రయోజనాలు, మరియు ఉత్తమ పద్ధతులను వివరిస్తుంది.

టైప్‌స్క్రిప్ట్ జెనెరిక్స్: బలమైన అనువర్తనాల కోసం సంక్లిష్ట డేటా రకాలను నేర్చుకోవడం

టైప్‌స్క్రిప్ట్, జావాస్క్రిప్ట్ యొక్క సూపర్‌సెట్, డెవలపర్‌లకు స్టాటిక్ టైపింగ్ ద్వారా మరింత బలమైన మరియు నిర్వహించదగిన కోడ్‌ను వ్రాయడానికి అధికారం ఇస్తుంది. దీని అత్యంత శక్తివంతమైన ఫీచర్లలో జెనెరిక్స్ ఒకటి, ఇది టైప్ సేఫ్టీని పాటిస్తూనే వివిధ రకాల డేటా రకాలతో పనిచేయగల కోడ్‌ను వ్రాయడానికి మిమ్మల్ని అనుమతిస్తుంది. ఈ గైడ్ టైప్‌స్క్రిప్ట్ జెనెరిక్స్‌పై సమగ్ర అన్వేషణను అందిస్తుంది, ఇది గ్లోబల్ సాఫ్ట్‌వేర్ డెవలప్‌మెంట్ సందర్భంలో సంక్లిష్ట డేటా రకాలకు వాటి అనువర్తనంపై దృష్టి పెడుతుంది.

జెనెరిక్స్ అంటే ఏమిటి?

వివిధ రకాలతో పనిచేయగల పునర్వినియోగ కోడ్‌ను వ్రాయడానికి జెనెరిక్స్ ఒక మార్గాన్ని అందిస్తాయి. మీరు మద్దతు ఇవ్వాలనుకుంటున్న ప్రతి రకానికి వేర్వేరు ఫంక్షన్‌లు లేదా క్లాస్‌లను వ్రాయడానికి బదులుగా, మీరు టైప్ పారామీటర్లను ఉపయోగించే ఒకే ఫంక్షన్ లేదా క్లాస్‌ను వ్రాయవచ్చు. ఈ టైప్ పారామీటర్లు ఫంక్షన్ లేదా క్లాస్‌ను పిలిచినప్పుడు లేదా ఇన్‌స్టాన్షియేట్ చేసినప్పుడు ఉపయోగించబడే అసలు రకాలకు ప్లేస్‌హోల్డర్‌లుగా ఉంటాయి. సంక్లిష్ట డేటా నిర్మాణాలతో వ్యవహరించేటప్పుడు ఇది చాలా ఉపయోగకరంగా ఉంటుంది, ఇక్కడ ఆ నిర్మాణాలలోని డేటా రకం మారవచ్చు.

జెనెరిక్స్ ఉపయోగించడం వల్ల ప్రయోజనాలు

జెనెరిక్స్ యొక్క ప్రాథమిక సింటాక్స్

జెనెరిక్స్ యొక్క ప్రాథమిక సింటాక్స్‌లో టైప్ పారామీటర్లను ప్రకటించడానికి యాంగిల్ బ్రాకెట్లను (< >) ఉపయోగించడం ఉంటుంది. ఈ టైప్ పారామీటర్లకు సాధారణంగా T, K, V, మొదలైన పేర్లు ఉంటాయి, కానీ మీరు ఏదైనా చెల్లుబాటు అయ్యే ఐడెంటిఫైయర్‌ను ఉపయోగించవచ్చు. ఇక్కడ ఒక జెనెరిక్ ఫంక్షన్ యొక్క సాధారణ ఉదాహరణ:


function identity<T>(arg: T): T {
  return arg;
}

let myString: string = identity<string>("hello");
let myNumber: number = identity<number>(123);
let myBoolean: boolean = identity<boolean>(true);

console.log(myString); // Output: hello
console.log(myNumber); // Output: 123
console.log(myBoolean); // Output: true

ఈ ఉదాహరణలో, <T> అనేది T అనే టైప్ పారామీటర్‌ను ప్రకటిస్తుంది. identity ఫంక్షన్ T రకం ఆర్గ్యుమెంట్‌ను తీసుకుని T రకం విలువను తిరిగి ఇస్తుంది. ఫంక్షన్‌ను పిలిచేటప్పుడు, మీరు టైప్ పారామీటర్‌ను స్పష్టంగా పేర్కొనవచ్చు (ఉదా., identity<string>) లేదా ఆర్గ్యుమెంట్ రకం ఆధారంగా టైప్‌స్క్రిప్ట్‌ను దానిని ఊహించనివ్వవచ్చు.

సంక్లిష్ట డేటా రకాలతో పనిచేయడం

అర్రేలు, ఆబ్జెక్ట్‌లు మరియు ఇంటర్‌ఫేస్‌ల వంటి సంక్లిష్ట డేటా రకాలతో వ్యవహరించేటప్పుడు జెనెరిక్స్ ప్రత్యేకంగా విలువైనవిగా మారతాయి. కొన్ని సాధారణ సందర్భాలను అన్వేషిద్దాం:

జెనెరిక్ అర్రేలు

మీరు వివిధ రకాల అర్రేలతో పనిచేసే ఫంక్షన్‌లు లేదా క్లాస్‌లను సృష్టించడానికి జెనెరిక్స్‌ను ఉపయోగించవచ్చు:


function arrayToString<T>(arr: T[]): string {
  return arr.join(", ");
}

let numberArray: number[] = [1, 2, 3, 4, 5];
let stringArray: string[] = ["apple", "banana", "cherry"];

console.log(arrayToString(numberArray)); // Output: 1, 2, 3, 4, 5
console.log(arrayToString(stringArray)); // Output: apple, banana, cherry

ఇక్కడ, arrayToString ఫంక్షన్ T[] రకం అర్రేను తీసుకుని, అర్రే యొక్క స్ట్రింగ్ ప్రాతినిధ్యాన్ని తిరిగి ఇస్తుంది. ఈ ఫంక్షన్ ఏ రకమైన అర్రేలతోనైనా పనిచేస్తుంది, ఇది అధికంగా పునర్వినియోగించదగినదిగా చేస్తుంది.

జెనెరిక్ ఆబ్జెక్ట్‌లు

వివిధ ఆకృతుల ఆబ్జెక్ట్‌లతో పనిచేసే ఫంక్షన్‌లు లేదా క్లాస్‌లను నిర్వచించడానికి కూడా జెనెరిక్స్‌ను ఉపయోగించవచ్చు:


interface Person {
  name: string;
  age: number;
  country: string; // Added country for global context
}

interface Product {
  id: number;
  name: string;
  price: number;
  currency: string; // Added currency for global context
}

function displayInfo<T extends { name: string }>(item: T): void {
  console.log(`Name: ${item.name}`);
}

let person: Person = { name: "Alice", age: 30, country: "USA" };
let product: Product = { id: 1, name: "Laptop", price: 1200, currency: "USD" };

displayInfo(person); // Output: Name: Alice
displayInfo(product); // Output: Name: Laptop

ఈ ఉదాహరణలో, displayInfo ఫంక్షన్ T రకం ఆబ్జెక్ట్‌ను తీసుకుంటుంది, దానికి తప్పనిసరిగా స్ట్రింగ్ రకం name ప్రాపర్టీ ఉండాలి. extends { name: string } క్లాజ్ ఒక కన్‌స్ట్రెయింట్, ఇది టైప్ పారామీటర్ T కోసం కనీస అవసరాలను నిర్దేశిస్తుంది. ఇది ఫంక్షన్ name ప్రాపర్టీని సురక్షితంగా యాక్సెస్ చేయగలదని నిర్ధారిస్తుంది.

అధునాతన జెనెరిక్ వాడకం

టైప్‌స్క్రిప్ట్ జెనెరిక్స్ మరింత అధునాతన ఫీచర్లను అందిస్తాయి, ఇవి మరింత ఫ్లెక్సిబుల్ మరియు శక్తివంతమైన కోడ్‌ను సృష్టించడానికి మిమ్మల్ని అనుమతిస్తాయి. ఈ ఫీచర్లలో కొన్నింటిని అన్వేషిద్దాం:

బహుళ టైప్ పారామీటర్లు

మీరు బహుళ టైప్ పారామీటర్లతో ఫంక్షన్‌లు లేదా క్లాస్‌లను నిర్వచించవచ్చు:


function merge<T, U>(obj1: T, obj2: U): T & U {
  return { ...obj1, ...obj2 };
}

interface Name {
  firstName: string;
}

interface Age {
  age: number;
}

const person: Name = { firstName: "Bob" };
const details: Age = { age: 42 };

const merged = merge(person, details);
console.log(merged.firstName); // Output: Bob
console.log(merged.age); // Output: 42

merge ఫంక్షన్ T మరియు U రకాల రెండు ఆబ్జెక్ట్‌లను తీసుకుంటుంది మరియు రెండు ఆబ్జెక్ట్‌ల ప్రాపర్టీలను కలిగి ఉన్న కొత్త ఆబ్జెక్ట్‌ను తిరిగి ఇస్తుంది. ఇది వివిధ వనరుల నుండి డేటాను కలపడానికి ఒక శక్తివంతమైన మార్గం.

జెనెరిక్ కన్‌స్ట్రెయింట్స్

ముందు చూపినట్లుగా, జెనెరిక్ టైప్ పారామీటర్‌తో ఉపయోగించగల రకాలను పరిమితం చేయడానికి కన్‌స్ట్రెయింట్స్ మిమ్మల్ని అనుమతిస్తాయి. ఇది మీ జెనెరిక్ కోడ్ నిర్దిష్ట రకాలపై సురక్షితంగా పనిచేయగలదని నిర్ధారిస్తుంది.


interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}

loggingIdentity([1, 2, 3]); // Output: 3
loggingIdentity("hello"); // Output: 5
// loggingIdentity(123); // Error: Argument of type 'number' is not assignable to parameter of type 'Lengthwise'.

loggingIdentity ఫంక్షన్ T రకం ఆర్గ్యుమెంట్‌ను తీసుకుంటుంది, దీనికి తప్పనిసరిగా నంబర్ రకం length ప్రాపర్టీ ఉండాలి. ఇది ఫంక్షన్ length ప్రాపర్టీని సురక్షితంగా యాక్సెస్ చేయగలదని నిర్ధారిస్తుంది.

జెనెరిక్ క్లాస్‌లు

జెనెరిక్స్‌ను క్లాస్‌లతో కూడా ఉపయోగించవచ్చు:


class DataStorage<T> {
  private data: T[] = [];

  addItem(item: T) {
    this.data.push(item);
  }

  removeItem(item: T) {
    this.data = this.data.filter(d => d !== item);
  }

  getItems(): T[] {
    return [...this.data];
  }
}

const textStorage = new DataStorage<string>();
textStorage.addItem("apple");
textStorage.addItem("banana");
textStorage.removeItem("apple");
console.log(textStorage.getItems()); // Output: [ 'banana' ]

const numberStorage = new DataStorage<number>();
numberStorage.addItem(1);
numberStorage.addItem(2);
numberStorage.removeItem(1);
console.log(numberStorage.getItems()); // Output: [ 2 ]

DataStorage క్లాస్ ఏ రకమైన T డేటానైనా నిల్వ చేయగలదు. ఇది టైప్-సేఫ్ అయిన పునర్వినియోగ డేటా నిర్మాణాలను సృష్టించడానికి మిమ్మల్ని అనుమతిస్తుంది.

జెనెరిక్ ఇంటర్‌ఫేస్‌లు

వివిధ రకాలతో పనిచేయగల కాంట్రాక్ట్‌లను నిర్వచించడానికి జెనెరిక్ ఇంటర్‌ఫేస్‌లు ఉపయోగపడతాయి. ఉదాహరణకు:


interface Result<T, E> {
  success: boolean;
  data?: T;
  error?: E;
}

interface User {
  id: number;
  username: string;
  email: string;
}

interface ErrorMessage {
  code: number;
  message: string;
}

function fetchUser(id: number): Result<User, ErrorMessage> {
  if (id === 1) {
    return { success: true, data: { id: 1, username: "john.doe", email: "john.doe@example.com" } };
  } else {
    return { success: false, error: { code: 404, message: "User not found" } };
  }
}

const userResult = fetchUser(1);
if (userResult.success) {
  console.log(userResult.data.username);
} else {
  console.log(userResult.error.message);
}

Result ఇంటర్‌ఫేస్ ఒక ఆపరేషన్ యొక్క ఫలితాన్ని సూచించడానికి ఒక జెనెరిక్ నిర్మాణాన్ని నిర్వచిస్తుంది. ఇది T రకం డేటాను లేదా E రకం ఎర్రర్‌ను కలిగి ఉండవచ్చు. ఇది ασύγχρονες ఆపరేషన్‌లు లేదా విఫలం కాగల ఆపరేషన్‌లను నిర్వహించడానికి ఒక సాధారణ పద్ధతి.

యుటిలిటీ రకాలు మరియు జెనెరిక్స్

టైప్‌స్క్రిప్ట్ జెనెరిక్స్‌తో బాగా పనిచేసే అనేక అంతర్నిర్మిత యుటిలిటీ రకాలను అందిస్తుంది. ఈ యుటిలిటీ రకాలు మీకు రకాలను శక్తివంతమైన మార్గాల్లో మార్చడానికి మరియు మార్పు చేయడానికి సహాయపడతాయి.

Partial<T>

Partial<T> T రకం యొక్క అన్ని ప్రాపర్టీలను ఐచ్ఛికంగా చేస్తుంది:


interface Person {
  name: string;
  age: number;
}

type PartialPerson = Partial<Person>;

const partialPerson: PartialPerson = { name: "Alice" }; // Valid

Readonly<T>

Readonly<T> T రకం యొక్క అన్ని ప్రాపర్టీలను రీడ్-ఓన్లీగా చేస్తుంది:


interface Person {
  name: string;
  age: number;
}

type ReadonlyPerson = Readonly<Person>;

const readonlyPerson: ReadonlyPerson = { name: "Bob", age: 42 };
// readonlyPerson.age = 43; // Error: Cannot assign to 'age' because it is a read-only property.

Pick<T, K>

Pick<T, K> T రకం నుండి K ప్రాపర్టీల సెట్‌ను ఎంపిక చేస్తుంది:


interface Person {
  name: string;
  age: number;
  email: string;
}

type NameAndAge = Pick<Person, "name" | "age">;

const nameAndAge: NameAndAge = { name: "Charlie", age: 28 };

Omit<T, K>

Omit<T, K> T రకం నుండి K ప్రాపర్టీల సెట్‌ను తొలగిస్తుంది:


interface Person {
  name: string;
  age: number;
  email: string;
}

type PersonWithoutEmail = Omit<Person, "email">;

const personWithoutEmail: PersonWithoutEmail = { name: "David", age: 35 };

Record<K, T>

Record<K, T> K కీలతో మరియు T రకం విలువలతో ఒక రకాన్ని సృష్టిస్తుంది:


type CountryCodes = "US" | "CA" | "UK" | "DE" | "FR" | "JP" | "CN" | "IN" | "BR" | "AU"; // Expanded list for global context
type Currency = "USD" | "CAD" | "GBP" | "EUR" | "JPY" | "CNY" | "INR" | "BRL" | "AUD"; // Expanded list for global context

type CurrencyMap = Record<CountryCodes, Currency>;

const currencyMap: CurrencyMap = {
  "US": "USD",
  "CA": "CAD",
  "UK": "GBP",
  "DE": "EUR",
  "FR": "EUR",
  "JP": "JPY",
  "CN": "CNY",
  "IN": "INR",
  "BR": "BRL",
  "AU": "AUD",
};

మ్యాప్డ్ రకాలు

మ్యాప్డ్ రకాలు ఇప్పటికే ఉన్న రకాల ప్రాపర్టీలపై ఇటరేట్ చేయడం ద్వారా వాటిని మార్చడానికి మిమ్మల్ని అనుమతిస్తాయి. ఇది ఇప్పటికే ఉన్న వాటి ఆధారంగా కొత్త రకాలను సృష్టించడానికి ఒక శక్తివంతమైన మార్గం. ఉదాహరణకు, మీరు మరొక రకం యొక్క అన్ని ప్రాపర్టీలను రీడ్-ఓన్లీగా చేసే రకాన్ని సృష్టించవచ్చు:


interface Person {
  name: string;
  age: number;
}

type ReadonlyPerson = {
  readonly [K in keyof Person]: Person[K];
};

const readonlyPerson: ReadonlyPerson = { name: "Eve", age: 25 };
// readonlyPerson.age = 26; // Error: Cannot assign to 'age' because it is a read-only property.

ఈ ఉదాహరణలో, [K in keyof Person] Person ఇంటర్‌ఫేస్ యొక్క అన్ని కీలపై ఇటరేట్ చేస్తుంది, మరియు Person[K] ప్రతి ప్రాపర్టీ యొక్క రకాన్ని యాక్సెస్ చేస్తుంది. readonly కీవర్డ్ ప్రతి ప్రాపర్టీని రీడ్-ఓన్లీగా చేస్తుంది.

కండిషనల్ రకాలు

కండిషనల్ రకాలు షరతుల ఆధారంగా రకాలను నిర్వచించడానికి మిమ్మల్ని అనుమతిస్తాయి. ఇది విభిన్న దృశ్యాలకు అనుగుణంగా రకాలను సృష్టించడానికి ఒక శక్తివంతమైన మార్గం.


type NonNullable<T> = T extends null | undefined ? never : T;

type MaybeString = string | null | undefined;
type StringType = NonNullable<MaybeString>; // string

function getValue<T>(value: T): NonNullable<T> {
  if (value == null) { // Handles both null and undefined
    throw new Error("Value cannot be null or undefined");
  }
  return value as NonNullable<T>;
}

try {
  const validValue = getValue("hello");
  console.log(validValue.toUpperCase()); // Output: HELLO

  const invalidValue = getValue(null); // This will throw an error
  console.log(invalidValue); // This line will not be reached
} catch (error: any) {
  console.error(error.message); // Output: Value cannot be null or undefined
}

ఈ ఉదాహరణలో, NonNullable<T> రకం T null లేదా undefined కాదా అని తనిఖీ చేస్తుంది. అది అయితే, అది neverను తిరిగి ఇస్తుంది, అంటే ఆ రకం అనుమతించబడదు. లేకపోతే, అది Tను తిరిగి ఇస్తుంది. ఇది మీకు నాన్-నల్లబుల్ అని హామీ ఇవ్వబడిన రకాలను సృష్టించడానికి అనుమతిస్తుంది.

జెనెరిక్స్ ఉపయోగించడానికి ఉత్తమ పద్ధతులు

జెనెరిక్స్ ఉపయోగించేటప్పుడు గుర్తుంచుకోవలసిన కొన్ని ఉత్తమ పద్ధతులు ఇక్కడ ఉన్నాయి:

గ్లోబల్ సందర్భంలో ఉదాహరణలు

గ్లోబల్ సందర్భంలో జెనెరిక్స్ ఎలా ఉపయోగించవచ్చో కొన్ని ఉదాహరణలను పరిశీలిద్దాం:

కరెన్సీ మార్పిడి


interface ConversionRate {
  rate: number;
  fromCurrency: string;
  toCurrency: string;
}

function convertCurrency<T extends ConversionRate>(amount: number, rate: T): number {
  return amount * rate.rate;
}

const usdToEurRate: ConversionRate = { rate: 0.85, fromCurrency: "USD", toCurrency: "EUR" };
const amountInUSD = 100;
const amountInEUR = convertCurrency(amountInUSD, usdToEurRate);
console.log(`${amountInUSD} USD is equal to ${amountInEUR} EUR`); // Output: 100 USD is equal to 85 EUR

తేదీ ఫార్మాటింగ్


interface DateFormatOptions {
  locale: string;
  options: Intl.DateTimeFormatOptions;
}

function formatDate<T extends DateFormatOptions>(date: Date, format: T): string {
  return date.toLocaleDateString(format.locale, format.options);
}

const currentDate = new Date();

const usDateFormat: DateFormatOptions = { locale: "en-US", options: { year: 'numeric', month: 'long', day: 'numeric' } };
const germanDateFormat: DateFormatOptions = { locale: "de-DE", options: { year: 'numeric', month: 'long', day: 'numeric' } };
const japaneseDateFormat: DateFormatOptions = { locale: "ja-JP", options: { year: 'numeric', month: 'long', day: 'numeric' } };

console.log("US Date: " + formatDate(currentDate, usDateFormat));
console.log("German Date: " + formatDate(currentDate, germanDateFormat));
console.log("Japanese Date: " + formatDate(currentDate, japaneseDateFormat));

అనువాద సేవ


interface Translation {
  [key: string]: string; // Allows for dynamic language keys
}

interface LanguageData<T extends Translation> {
  languageCode: string;
  translations: T;
}

const englishTranslations: Translation = {
  "hello": "Hello",
  "goodbye": "Goodbye",
  "welcome": "Welcome to our website!"
};

const spanishTranslations: Translation = {
  "hello": "Hola",
  "goodbye": "Adiós",
  "welcome": "¡Bienvenido a nuestro sitio web!"
};

const frenchTranslations: Translation = {
  "hello": "Bonjour",
  "goodbye": "Au revoir",
  "welcome": "Bienvenue sur notre site web !"
};


const languageData: LanguageData<typeof englishTranslations>[] = [
  {languageCode: "en", translations: englishTranslations },
  {languageCode: "es", translations: spanishTranslations },
  {languageCode: "fr", translations: frenchTranslations}
];

function translate<T extends Translation>(key: string, languageCode: string, languageData: LanguageData<T>[]): string {
  const lang = languageData.find(lang => lang.languageCode === languageCode);
  if (!lang) {
    return `Translation for ${key} in ${languageCode} not found.`;
  }
  return lang.translations[key] || `Translation for ${key} not found.`;
}

console.log(translate("hello", "en", languageData)); // Output: Hello
console.log(translate("hello", "es", languageData)); // Output: Hola
console.log(translate("welcome", "fr", languageData)); // Output: Bienvenue sur notre site web !
console.log(translate("missingKey", "de", languageData)); // Output: Translation for missingKey in de not found.

ముగింపు

టైప్‌స్క్రిప్ట్ జెనెరిక్స్ అనేవి పునర్వినియోగించదగిన, టైప్-సేఫ్ కోడ్‌ను వ్రాయడానికి ఒక శక్తివంతమైన సాధనం, ఇది సంక్లిష్టమైన డేటా రకాలతో పనిచేయగలదు. జెనెరిక్స్ యొక్క ప్రాథమిక సింటాక్స్, అధునాతన ఫీచర్లు మరియు ఉత్తమ పద్ధతులను అర్థం చేసుకోవడం ద్వారా, మీరు మీ టైప్‌స్క్రిప్ట్ అప్లికేషన్‌ల నాణ్యత మరియు నిర్వహణ సామర్థ్యాన్ని గణనీయంగా మెరుగుపరచవచ్చు. గ్లోబల్ ప్రేక్షకుల కోసం అప్లికేషన్‌లను అభివృద్ధి చేసేటప్పుడు, జెనెరిక్స్ విభిన్న డేటా ఫార్మాట్‌లు మరియు సాంస్కృతిక సంప్రదాయాలను నిర్వహించడంలో మీకు సహాయపడతాయి, అందరికీ ఒక అతుకులు లేని వినియోగదారు అనుభవాన్ని నిర్ధారిస్తాయి.